#include <jni.h>
#include <string>
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <fcntl.h>


#include <sys/stat.h>
#include <sys/mman.h>

#include <pthread.h>
#include <stdlib.h>
#include "objectarray.h"

#include "uvccamera-lib.h"
#include "lane.h"
//libyuv
#include "mjpeg_decoder.h"
#include <libyuv/basic_types.h>
#include "libyuv/include/libyuv.h"


#if 1

ANativeWindow *aNativeWindow;
pthread_t t_getdata, t_display, t_notifyAudio;
bool isPreviewing = false;
bool isMainRunning = false;
bool isPx3 = false;
//px3 change
#endif


JavaVM *javaVM;
jclass callbackclass;
jmethodID jd_callback;

jobject mFrameCallbackObj;
jmethodID md_callback;

jobject mAdasCallbackObj;
jmethodID mdAdas_callback;

jobject mStateCallbackObj;
jmethodID mdState_callback;




jbyteArray adasBuffer = NULL;

#if ANTHOER_MJ2YUV_EN
mjpeg_decoder mjpegDecoder;
#endif

char *snapshotBuffer = NULL;
int snapshotSize = 0;
bool isSnapshot = FALSE;

char *cmdbuffer = NULL;
size_t CMD_DATA_LEN = 20480 ; // 20KB

int cmdFd = -1 ;


//++++++++++++++

u8 audioBuff[8192] = {0} ;
bool isAudioUpdate = FALSE;

static bool isAnNumFlag = TRUE ;

#if LANE_DETECT_EN

	LANE_DATA laneData ;
	u8 isReport = 0;
	u8 isReportEnd = 0;
#endif



	static bool isUpLoadAdasData = 0 ;

static int  boardVer=0 ;


static u8 isReadVsDataAndDecode = 1 ;
//-------------------

#include "libyuv/include/libyuv.h"
using namespace libyuv;


//????????????
struct Instance *instance = NULL;


extern "C" {


#include <unistd.h>
#include "libuvc.h"
#include <time.h>
#include "opengles/cameraShader.h"
#include "utilbase.h"


pthread_mutex_t pool_mutex;
pthread_mutex_t preview_mutex;
pthread_mutex_t capture_mutex;

pthread_mutex_t adas_mutex;
pthread_mutex_t yuv_mutex;
pthread_mutex_t cmd_mutex;


pthread_mutex_t decode_mutex;


pthread_cond_t preview_sync;
pthread_cond_t adas_sync;
pthread_cond_t cmd_sync;

pthread_cond_t snap_sync;
pthread_mutex_t snap_mutex;
int framewidth = 1280, frameheight = 720;
void *getDataThread(void *);
void *displayThread(void *);
void *adasThread(void *);

void *notifyAudioData2AppThread(void *);


ObjectArray<uvc_frame_t *> previewFrames;
ObjectArray<uvc_frame_t *> mAdasFrames;
ObjectArray<uvc_frame_t *> mYuvFrames;
ObjectArray<uvc_frame_t *> mFramePool;


JavaVM *getVm();

extern const char *codeVertexShader;
extern const char *codeFragShader;



JavaVM *getVm() {
    return javaVM;
}


void setBoardVer(int val){
	boardVer = val ;
}

// 0: old Ver - 1: new Ver
int getBoardVer(void){
	return boardVer ;
}



void recycle_frame(uvc_frame_t *frame) {
    pthread_mutex_lock(&pool_mutex);
    if (LIKELY(mFramePool.size() < FRAME_POOL_SZ)) {
        mFramePool.put(frame);
        frame = NULL;
    }
    pthread_mutex_unlock(&pool_mutex);
    if (UNLIKELY(frame)) {
        uvc_free_frame(frame);
    }
}
void addPreviewFrame(uvc_frame_t *frame) {

    pthread_mutex_lock(&preview_mutex);
    if (isPreviewing && (previewFrames.size() < MAX_FRAME)) {
        previewFrames.put(frame);
        frame = NULL;
        pthread_cond_signal(&preview_sync);
    }
    pthread_mutex_unlock(&preview_mutex);
    if (frame) {
        recycle_frame(frame);
    }
}

uvc_frame_t *waitPreviewFrame() {
    uvc_frame_t *frame = NULL;
    pthread_mutex_lock(&preview_mutex);
    {
        if (!previewFrames.size()) {
            pthread_cond_wait(&preview_sync, &preview_mutex);
        }
        if (LIKELY(isPreviewing && previewFrames.size() > 0)) {
            frame = previewFrames.remove(0);
        }
    }
    pthread_mutex_unlock(&preview_mutex);
    return frame;
}

#if UPLOAD_ADAS_DATA_EN

void addAdasFrame(uvc_frame_t *frame) {

    pthread_mutex_lock(&adas_mutex);
//    int max=frame->frame_format==UVC_FRAME_FORMAT_MJPEG?2:MAX_FRAME;
    //if (isPreviewing && (mAdasFrames.size() < 1)) {
    if (isPreviewing && (mAdasFrames.size() < 3)) {
        mAdasFrames.put(frame);
        frame = NULL;
        pthread_cond_signal(&adas_sync);
    }
    pthread_mutex_unlock(&adas_mutex);
    if (frame) {
        recycle_frame(frame);
    }
}

uvc_frame_t *waitAdasFrame() {
    uvc_frame_t *frame = NULL;
    pthread_mutex_lock(&adas_mutex);
    {
        if (!mAdasFrames.size()) {
            pthread_cond_wait(&adas_sync, &adas_mutex);
        }
        if (LIKELY(isPreviewing && mAdasFrames.size() > 0)) {
            frame = mAdasFrames.remove(0);
        }
    }
    pthread_mutex_unlock(&adas_mutex);
    return frame;
}

#endif

void addYuvFrame(uvc_frame_t *frame) {

    pthread_mutex_lock(&yuv_mutex);
    //if (isPreviewing && (mYuvFrames.size() < 4)) {
    if (isPreviewing && (mYuvFrames.size() < (cacheFrameCnt+1))) {//lgz 0207
        mYuvFrames.put(frame);
        frame = NULL;
//        pthread_cond_signal(&adas_sync);
    }
    pthread_mutex_unlock(&yuv_mutex);
    if (frame) {
//        LOGE("recycle frame");
        recycle_frame(frame);
    }
}

uvc_frame_t *waitYuvFrame() {
    uvc_frame_t *frame = NULL;
    pthread_mutex_lock(&yuv_mutex);
    {
//        if (!mAdasFrames.size()) {
//            pthread_cond_wait(&adas_sync, &adas_mutex);
//        }
#if 0
        if (LIKELY(isPreviewing && mYuvFrames.size() > 0)) {
            frame = mYuvFrames.remove(0);
        }
#else // 0207 test
		if (LIKELY(isPreviewing && mYuvFrames.size() > cacheFrameCnt)) {
			frame = mYuvFrames.remove(0);
		}
#endif
    }
    pthread_mutex_unlock(&yuv_mutex);
    return frame;
}

uvc_frame_t *get_frame(size_t data_bytes) {
    uvc_frame_t *frame = NULL;
    pthread_mutex_lock(&pool_mutex);
    {
        if (!mFramePool.isEmpty()) {
            frame = mFramePool.last();
        }
    }
    pthread_mutex_unlock(&pool_mutex);
    if UNLIKELY(!frame) {
        //LOGW("allocate new frame");
        frame = uvc_allocate_frame(data_bytes);
    }
    return frame;
}

void clearPreviewFrame() {
    pthread_mutex_lock(&preview_mutex);
    if(previewFrames.size()>0)// fv_add 20181010
    {
        for (int i = 0; i < previewFrames.size(); i++)
            recycle_frame(previewFrames[i]);
        previewFrames.clear();
    }
    pthread_mutex_unlock(&preview_mutex);

#if 1 //lgz adas
    pthread_mutex_lock(&adas_mutex);
    if(mAdasFrames.size()>0)// fv_add 20181010
    {
        for (int i = 0; i < mAdasFrames.size(); i++)
            recycle_frame(mAdasFrames[i]);
        mAdasFrames.clear();
    }
    pthread_mutex_unlock(&adas_mutex);
#endif

    pthread_mutex_lock(&yuv_mutex);
	if(mYuvFrames.size()>0)// fv_add 20181010
    {
        for (int i = 0; i < mYuvFrames.size(); i++)
            recycle_frame(mYuvFrames[i]);
        mYuvFrames.clear();
    }
    pthread_mutex_unlock(&yuv_mutex);
}




/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
//    LOGE("JNI_OnLoad");
    JNIEnv *env = NULL;
    jint result = -1;
    javaVM = vm;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    if (env) {
        jclass uvc = env->FindClass("com/huiying/cameramjpeg/UvcCamera");
        if (uvc != NULL) {
            callbackclass = uvc;
            jd_callback = env->GetStaticMethodID(uvc, "onFrameData", "([B)V");
        }
    }
    /* success -- return valid version number */
    result = JNI_VERSION_1_6;

//    LOGE("JNI_OnLoad end");
    return result;
}


void ProcessCommand(char *pBufAddr) {
#if 1
    JavaVM *vm = getVm();
    JNIEnv *env = NULL;
    if (vm) {
        vm->AttachCurrentThread(&env, NULL);
        if (env && mStateCallbackObj && mdState_callback) {
            jbyteArray bytes = env->NewByteArray(512);
            env->SetByteArrayRegion(bytes, 0, 512,
                                    (const jbyte *) pBufAddr);
            env->CallVoidMethod(mStateCallbackObj, mdState_callback, bytes);
            env->DeleteLocalRef(bytes);
        }
        vm->DetachCurrentThread();
    } else {
        //LOGE("ProcessCommand error...");
    }

#endif
}


void *notifyAudioData2AppThread(void* _fd){
	long fd = (long) _fd;
	debugl("notifyAudioData2AppThread - start") ;
	while(fd && isPreviewing){

		if(isAudioUpdate ){
			JavaVM *vm = getVm();
			JNIEnv *env = NULL;
			if (vm) {
				vm->AttachCurrentThread(&env, NULL);
				if (env && mFrameCallbackObj && md_callback) {
					jbyteArray bytes = env->NewByteArray(8184);
					env->SetByteArrayRegion(bytes, 0, 8184,
											(const jbyte *) audioBuff);
					env->CallVoidMethod(mFrameCallbackObj, md_callback, bytes);
					env->DeleteLocalRef(bytes);
				}
				vm->DetachCurrentThread();
			} else {
//				LOGE("env && mAdasCallbackObj && mdAdas_callback  f");
			}
			isAudioUpdate = FALSE ;
		}else{
			usleep(25*1000);//10 ms
		}
	}
	debugl("notifyAudioData2AppThread - end") ;
	pthread_exit(0) ;
	return NULL;
}


bool isAnNum(u16 num){

	u8 value = (num>>8)&0xff ;
	u8 index = num&0xff ;
	
	u8 sum=0 , i , outdata=0x00 ;
    u8 tempdata = (value>>5) ;    
	outdata |= tempdata^0x0B ;                                                                   
    for(i=0 ; i<5 ; i++) 
		sum += (value>>i)&0x01 ;
	outdata |= ((sum^0x0C) << 3);
	
	if(outdata == index)
		return TRUE ;
	else
		return FALSE ;
}

void cacheFrameCntHandler(int signo)
{
	cacheFrameCnt=0 ;
    //debugl("cacheFrameCnt-- [%d] - sgid:[%d]\n", cacheFrameCnt , signo);
}

int readFrameData(int fd , u8* bufAddr , u32 frameSize){
	int rlen ;
	if(frameSize > PER_CNT_READ_SIZE)
	{
		int haveReadSize=0  ;
		while(frameSize > haveReadSize){							
			rlen = read(fd, ((u8 *) bufAddr + haveReadSize) , \
			(frameSize - haveReadSize)>PER_CNT_READ_SIZE ? \
			PER_CNT_READ_SIZE :(frameSize - haveReadSize)) ;
			haveReadSize += rlen ;
			if(rlen<0){
				break ;
			}
		}	
		rlen = haveReadSize ;
	}else{
		rlen = read(fd, (u8 *) bufAddr , frameSize);					
	}

	return 1 ;
}


bool getVerApi(u32 fd){
	u32 i=0 , bufferLen=512 , wlen=0 ;
	u8* tmpBuffer = NULL ;
	if(fd<0){
		return FALSE ;
	}
	if (tmpBuffer == NULL)
		int nTemp = posix_memalign((void **) &tmpBuffer, getpagesize(), bufferLen);


	if(tmpBuffer){
		memset(tmpBuffer, 0, bufferLen);
		while(i<10){
			if( read(fd , tmpBuffer , bufferLen) == bufferLen){
				P_vsd_state tmpVsdState = (P_vsd_state)tmpBuffer ;
				debugl(" --- boardVer : [%d] ---" , tmpVsdState->App_lib) ;
				debugl(" --- boardVerCode : [%d] ---" , tmpVsdState->verCode) ;
				debugl(" --- boardVerName : [%s] ---" , tmpVsdState->devName) ;
				if(tmpVsdState->App_lib == 233){
					setBoardVer(1) ;
				}
				return TRUE ;
			}
			i++ ;
		}
	}

	if(tmpBuffer != NULL){
		free(tmpBuffer) ;
		tmpBuffer = NULL ;
	}
	

    return TRUE ;
}




#if 1
void *getDataThread(void *_fd) {
    long fd = (long) _fd;
    int frameCount = 0;
    int blocksize = 4 * getpagesize();
    //LOGE("get data thread tid=%d", gettid());

	u32 videoFrameNo = 0 ;
	u32 audioFrameNo = 0 ;
	int rlen = 0 ;
	u32 tmpIndex = 0 ;
	u32 readFlagIndex = 0 ;

	int bwTime =0 ;
	int bwFpsCount =0 ;

	struct timeval xTime ;
	int xRet ;
#if ADJ_CACHE_CNT_EN
	cacheFrameCnt = CACHE_FRAME_CNT ;
	u8 tttCacheBufferCnt = 0 ;
	int readTime1=0 , readTime2=0 ;
#else
	cacheFrameCnt = 0 ;
#endif	

    debugl("getDataThread - start") ;
	
    if (fd > 0) {
        const int DATA_LEN = 300 * 1024; //300kb
        unsigned char *pData = NULL;
       	int nTemp = posix_memalign((void **) &pData, 512, DATA_LEN);

        while (isPreviewing) {
			tmpIndex++ ;
            lseek(fd, 0, SEEK_SET);//0
            memset(pData, 0, 512);

#if ADJ_CACHE_CNT_EN
			xRet = gettimeofday(&xTime, NULL);
			readTime1 = (xTime.tv_sec- 312739200)*1000 + xTime.tv_usec/1000 ;

			if(1){
				int res = 0;
				struct itimerval tick;

				//kill timer
				memset(&tick, 0, sizeof(tick)); 
				setitimer(ITIMER_REAL, &tick, NULL);  		
						
				//new a timer	
				//Timeout to run first time
				tick.it_value.tv_sec = 0;
				tick.it_value.tv_usec = 100*1000 ; // unit: ms
				//After first, the Interval time for clock
				tick.it_interval.tv_sec = 0;
				tick.it_interval.tv_usec = 0;

				signal(SIGALRM, cacheFrameCntHandler);
				if(setitimer(ITIMER_REAL, &tick, NULL) < 0)
					debugl("Set timer failed!\n");
			}
			
#endif			
			//read header
            int readlen = read(fd, pData, 512);
#if 0
			if(readlen< 0){
			//	debugl("read len : %d - err:%s " , rlen , strerror(rlen)) ;
				//ProcessCommand((u8*)statusBuff);
				close(fd) ;
				break ;
			}
#endif

			_vsd_state *state = (_vsd_state *) pData;  

/*filter wrong data...*/
//++++++++++++++++++++++++++++++++
#if 1
	if((state->audioFrameSize != 8192 && state->audioFrameSize != 0) \
		|| (state->videoFrameSize>300*1024) || (state->state==0) || (state->videoFrameSize==0) \
	){
		usleep(10*1000);
		continue ;
	}
#endif	
//------------------------------------------


/*upload statusData...*/
//++++++++++++++++++++++++++++++++
#if LANE_DETECT_EN
	if(isReport == 1){
		state->isReport = isReport ;
		ProcessCommand( (char*)pData);
		tmpIndex = 0 ;
		isReport = 0 ;
	//	debugl("upload report...[%d]" ,*((u8*)pData+50) ) ;
	}		
#endif		

	if(tmpIndex > 20 && readlen>0){
		ProcessCommand( (char*)pData);
		tmpIndex = 0 ;
	}
//-------------------------------------------- 



//+++++++++++++++++++++++++++++++++++
#if SUPPORT_DECODE_SWITCH_EN
{
	pthread_mutex_lock(&decode_mutex);
	if(isReadVsDataAndDecode == 0){
		pthread_mutex_unlock(&decode_mutex) ;
		usleep(20*1000);
		continue ;
	}
	pthread_mutex_unlock(&decode_mutex) ;
}
#endif
//----------------------------------------------



            uint32 videoFrameSize = state->videoFrameSize;
            uint32 audioFrameSize = state->audioFrameSize;
            frameCount = state->videoFrameSize;

/*audio data*/
//++++++++++++++++++++++++++++++++
	if (audioFrameSize == 8192 && state->audioFrameNo > audioFrameNo) {

        rlen = read(fd, (u8 *) (&pData[512]), 8192);
		if(rlen>0){
			memcpy(audioBuff , &pData[512] , 8192) ;
            audioFrameNo = state->audioFrameNo  ;
			isAudioUpdate = TRUE ;
		}
    }
//------------------------------------------

/*filter same frame*/
//++++++++++++++++++++++++++++++++
#if 1
	if(state->videoFrameNo > videoFrameNo){
		videoFrameNo = state->videoFrameNo ;
		readFlagIndex = 0 ;
	}else{
		usleep(20*1000);
		if(state->state & 0x8000){// playback mode 
			continue ;
		}else{
			readFlagIndex++ ;
			if(readFlagIndex<=20){
				continue ;
			}else{
				readFlagIndex = 0 ;
				lseek(fd, 512 * 17, SEEK_SET) ;
				blocksize = ((frameCount >> 9) + 10 )<<9 ;
				readFrameData( fd , (u8 *)(&pData[1024]) , blocksize) ;
				continue ;
			}
		}
	}
#endif
//------------------------------------------


/*check*/
//++++++++++++++++++++++++++++++++
#if 1
			if( isAnNum(state->num) == FALSE ){
				debugl("check error...:0x%04X" , state->num) ;
				isAnNumFlag = FALSE ;
				continue ;
			}else{
				isAnNumFlag = TRUE ;
			}
#endif
//------------------------------------------


	            blocksize = ((frameCount >> 9) + 1 )<<9;
	            lseek(fd, 512 * 17, SEEK_SET);

/*read real frame data*/
//++++++++++++++++++++++++++++++++
#if 1
				uvc_frame_t *mjpegframe = get_frame(framewidth * frameheight * PREVIEW_PIXEL_BYTES );				
                mjpegframe->frame_format = UVC_FRAME_FORMAT_MJPEG;
                mjpegframe->width = framewidth;
                mjpegframe->height = frameheight;
				rlen = 0 ;


				if(blocksize > PER_CNT_READ_SIZE)
				{
					u32 haveReadSize=0  ;
					while(blocksize > haveReadSize){							
						rlen = read(fd, ((u8 *) mjpegframe->data + haveReadSize) , \
						(blocksize - haveReadSize)>PER_CNT_READ_SIZE ? \
						PER_CNT_READ_SIZE :(blocksize - haveReadSize)) ;
#if 0
						if(rlen< 0){ // fv_add 20181010
					//		debugl("read len : %d - err:%s " , rlen , strerror(rlen)) ;
							//ProcessCommand((u8*)statusBuff);
							close(fd) ;
							break ;
						}
#endif						
						haveReadSize += rlen ;
					}	
					rlen = haveReadSize ;
				}else{
					rlen = read(fd, (u8 *) mjpegframe->data , blocksize);
#if 0
					if(rlen< 0){ // fv_add 20181010
							//debugl("read len : %d - err:%s " , rlen , strerror(rlen)) ;
							close(fd) ;
							break ;
					}
#endif					
				}
//------------------------------------------




//+++++++++++++++++
#if ADJ_CACHE_CNT_EN
{
			xRet = gettimeofday(&xTime, NULL);
			readTime2 = (xTime.tv_sec- 312739200)*1000 + xTime.tv_usec/1000 ;
			int tttTime = readTime2 - readTime1 ;

			u32 ttt = 0 ;
			if(tttTime > 0){
				ttt = state->videoFrameSize/tttTime ;
			}else{
				ttt = 0 ;
			}
			tttCacheBufferCnt++ ;
			if( ttt>1000 && cacheFrameCnt<CACHE_FRAME_CNT && tttCacheBufferCnt>15){
				cacheFrameCnt++ ;
				tttCacheBufferCnt=0 ;
				//debugl("cacheFrameCnt++:[%d] , time:[%d] - size:[%d]KB - [%d]" , \
				//	cacheFrameCnt , tttTime , state->videoFrameSize>>10 , ttt ) ;
			}
			
}			
#endif
//----------------------


//frameData Check
//++++++++++++++++
#if 1

            u32 tmp = (state->videoFrameSize-8)/4 ;
			if((state->mjpegCheckData != *((u32*)mjpegframe->data+tmp) && !(state->state & 0x8000))  ){
	
		//		debugl("frameNo:%d - frameSize:%d - checkData:0x%X - curData:0x%X" , \
		//			state->videoFrameNo , state->videoFrameSize , \
		//			state->mjpegCheckData , *((u32*)mjpegframe->data+tmp) \
		//		) ;
				recycle_frame(mjpegframe);				
				continue ;
			}
#endif
//---------------------

				if(rlen>0){
					mjpegframe->actual_bytes = frameCount;

					if(state->state & 0x8000)
						mjpegframe->step = 111 ; // playBack Mode ;
					else
						mjpegframe->step = 100 ; // preview Mode ;

#if UPLOAD_MJPEG_DATA_EN
					if(state->state & 0x8000 ){ // playback mode
						addPreviewFrame(mjpegframe);
					}else{ // preview
						uvc_frame_t *jpegFrame = get_frame(framewidth * frameheight * PREVIEW_PIXEL_BYTES );
						jpegFrame->step = 100 ; 
						memcpy(jpegFrame->data , mjpegframe->data , mjpegframe->actual_bytes) ;
						jpegFrame->actual_bytes = frameCount ;
						addAdasFrame(jpegFrame) ;
						recycle_frame(mjpegframe) ;
					}
#else
					addPreviewFrame(mjpegframe);
#endif

										
					
					

				}
#endif
        }
        free(pData);
        LOGE("get data end");
    }
	pthread_exit(0) ;
    return NULL;
}
#endif

static u32 adasFrameCount = 1 ;
void *displayThread(void *_fd) {
    if (LIKELY(aNativeWindow)) {
        ANativeWindow_setBuffersGeometry(aNativeWindow,
                                         framewidth, frameheight, WINDOW_FORMAT_RGB_565);
    }
    LOGE("display thread tid=%d", gettid());
    while (isPreviewing) {
        uvc_frame_t *frame = waitPreviewFrame();

        if (frame) {
			usleep(2*1000) ; //3ms
            uvc_frame_t *yuvframe = get_frame(framewidth * frameheight * PREVIEW_PIXEL_BYTES);

            if (isSnapshot) {
                pthread_mutex_lock(&snap_mutex);
                snapshotSize = frame->actual_bytes;
                memcpy(snapshotBuffer, frame->data, snapshotSize);
                isSnapshot = FALSE;
                pthread_cond_signal(&snap_sync);
                pthread_mutex_unlock(&snap_mutex);
            }


#if ANTHOER_MJ2YUV_EN
//depend jpegTurbo
int ret=mjpegDecoder.mjpeg2yuv2((const unsigned char *) frame->data, frame->actual_bytes,
                                (unsigned char *) yuvframe->data,
                                frame->width, frame->height);
	//debugl("mjpeg2yuv2: - w:%d - h:%d" , frame->width, frame->height) ;
#else
	/*
		src_addr , dst_size ,
		dstY_addr , y_size ,
		dstU_addr , u_size ,
		dstV_addr , y_size ,
		src_w , src_h ,
		dst_w , dst_h
	*/
	#if DECODE_YUV420P_EN //YUV420P [Y : U : V]
		int ret = MJPGToI420( (uint8 *) frame->data , frame->actual_bytes	, \
			(uint8 *) yuvframe->data	, frame->width ,	\
			&((uint8 *) yuvframe->data)[frame->width * frame->height] , frame->width / 2	,	\
			&((uint8 *) yuvframe->data)[frame->width * frame->height * 5 / 4] , frame->width / 2 , \
			frame->width , frame->height , \
			frame->width	, frame->height );
	#else // YV12 [Y : V : U]
		int ret = MJPGToI420( (uint8 *) frame->data , frame->actual_bytes	, \
			(uint8 *) yuvframe->data	, frame->width ,	\
			&((uint8 *) yuvframe->data)[frame->width * frame->height * 5 / 4] , frame->width / 2 , \
			&((uint8 *) yuvframe->data)[frame->width * frame->height] , frame->width / 2	,	\
			frame->width , frame->height , \
			frame->width	, frame->height );	
	#endif

#endif


            if (ret == 0) {
			
                yuvframe->actual_bytes = framewidth * frameheight * PREVIEW_PIXEL_BYTES;
            
                yuvframe->width = frame->width;
                yuvframe->height = frame->height;
				addYuvFrame(yuvframe);
				
#if UPLOAD_ADAS_DATA_EN	//lgz for adas			
	#if UPLOAD_MJPEG_DATA_EN


	#else
				if(isUpLoadAdasData && (frame->step == 100) ){// preview mode
					#if 0
						if(adasFrameCount >= 3){//[3:upload 6-7 fps] [2:upload 10 fps] [1:upload 20 fps]
							uvc_frame_t *adasframe = get_frame(framewidth * frameheight * PREVIEW_PIXEL_BYTES);
							memcpy(adasframe->data, yuvframe->data, yuvframe->actual_bytes);
							adasframe->actual_bytes = yuvframe->actual_bytes;
							addAdasFrame(adasframe) ;
							adasFrameCount = 1 ;
						}else{
							adasFrameCount++ ;
						}
					#else
						if(adasFrameCount < 4){//[5:upload 16 fps] [4:upload 15 fps] 
							uvc_frame_t *adasframe = get_frame(framewidth * frameheight * PREVIEW_PIXEL_BYTES);
							memcpy(adasframe->data, yuvframe->data, yuvframe->actual_bytes);
							adasframe->actual_bytes = yuvframe->actual_bytes;
							addAdasFrame(adasframe) ;
							adasFrameCount++ ; //
						}else{
							adasFrameCount = 1 ;
						}					
					#endif
	            }
	#endif	
#endif
            } else {
                recycle_frame(yuvframe);
            }

            recycle_frame(frame);
        }else{
			usleep(15*1000);//30 ms
		}

    }
    LOGE("display end");
	pthread_exit(0) ;
    return NULL;
}

#if UPLOAD_ADAS_DATA_EN
void *adasThread(void *_fd) {
    for (; isPreviewing;) {
        uvc_frame_t *frame = waitAdasFrame();
        if (frame) {
            pthread_mutex_lock(&capture_mutex);
#if 1
            JavaVM *vm = getVm();
            JNIEnv *env = NULL;
            if (vm) {
                vm->AttachCurrentThread(&env, NULL);
                if (env && mAdasCallbackObj && mdAdas_callback) {
                    jbyteArray bytes = env->NewByteArray(frame->actual_bytes);
                    env->SetByteArrayRegion(bytes, 0, frame->actual_bytes,
                                            (const jbyte *) frame->data);
                    env->CallVoidMethod(mAdasCallbackObj, mdAdas_callback, bytes);
                    env->DeleteLocalRef(bytes);
                }
                vm->DetachCurrentThread();
            }
#endif
            recycle_frame(frame);
            pthread_mutex_unlock(&capture_mutex);
        }else{
			usleep(10*1000) ; //20ms
		}		
    }
	pthread_exit(0) ;
}

#endif


JNIEXPORT jstring JNICALL
Java_com_huiying_cameramjpeg_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}



JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_setDisplaySurface(JNIEnv *env, jobject instance,
                                                         jobject surface) {
    pthread_mutex_lock(&preview_mutex);
    if (surface) {
		aNativeWindow = ANativeWindow_fromSurface(env, surface);
		ANativeWindow_setBuffersGeometry(aNativeWindow,\
				framewidth, frameheight, WINDOW_FORMAT_RGB_565);
    } else {
        aNativeWindow = NULL;
    }
    pthread_mutex_unlock(&preview_mutex);
}


JNIEXPORT jstring JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_initUvcCamera(JNIEnv *env, jobject instance,
                                                     jstring _devpath) {
    pthread_mutex_init(&cmd_mutex, NULL);
    pthread_cond_init(&cmd_sync, NULL);
    int fd = -1;
    const char *devpath = env->GetStringUTFChars(_devpath, FALSE);
//    LOGE("start init uvccamera devpath=%s", devpath);
    struct stat info;
    int ret = stat(devpath, &info);
    if (devpath != NULL) {
        if(isPx3){
            fd = open(devpath, O_RDONLY | O_DIRECT | O_NOCTTY);
        } else{
            fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY,
                      S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        }


        if (fd == -1) {
//            LOGE("open readonly");
            if(isPx3){
                fd = open(devpath, O_DIRECT | O_NOCTTY);
            } else{
                fd = open(devpath, O_DIRECT | O_NOCTTY,
                          S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
            }

        }

		if(fd != -1){
			getVerApi(fd) ;
		}
		
//        uvcPreview.initCamera(devpath);
//        LOGE("init uvccamera fd=%d,errorcode=%d", fd, errno);
    }
    env->ReleaseStringUTFChars(_devpath, devpath);
    char result[50];
    char* error = strerror(errno);
    sprintf(result,"%d_%s",fd,error);
    //env->NewStringUTF(strerror(errno)
    return env->NewStringUTF(result);
//    return fd;
}



jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_startPreview(JNIEnv *env, jobject instance, jint fd) {
    isPreviewing = true;
//    LOGE("UvcCamera_startPreview fd=%d", fd);
    pthread_attr_t thread_attr;
    struct sched_param schedule_param;

    pthread_attr_init(&thread_attr);
    schedule_param.sched_priority = -1;
//    pthread_attr_setinheritsched(&thread_attr, PTHREAD_EXPLICIT_SCHED); //???????????????????????????????????????
    pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);
    pthread_attr_setschedparam(&thread_attr, &schedule_param);
    int ret = pthread_create(&t_getdata, &thread_attr, &getDataThread, (void *) fd);

    int ret1 = pthread_create(&t_display, NULL, &displayThread, NULL);

	int ret2 = pthread_create(&t_notifyAudio , NULL , &notifyAudioData2AppThread , (void *) fd) ;//lgz audio

    pthread_setschedparam(t_display, SCHED_FIFO, &schedule_param);

#if UPLOAD_ADAS_DATA_EN //adas
    pthread_t t_adas = NULL;
    int adas = pthread_create(&t_adas, NULL, &adasThread, NULL);
    pthread_detach(t_display);
#endif
	initlanePosData() ;
    return ret;
}



JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_stopPreview(JNIEnv *env, jobject instance, jint fd) {
    pthread_mutex_lock(&preview_mutex);
    if (LIKELY(isPreviewing)) {
        isPreviewing = false;
        pthread_cond_signal(&preview_sync);
        pthread_cond_signal(&adas_sync);
    }
    if (aNativeWindow) {
        ANativeWindow_release(aNativeWindow);
        aNativeWindow = NULL;
    }
    pthread_mutex_unlock(&preview_mutex);
    return 0;
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_GetStatus(JNIEnv *env, jobject instance, jint fd) {
    return 0 ; //mystate;
}


JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_releaseUvcCamera(JNIEnv *env, jobject instance, jint fd) {
	int ret=0 ;

	if(cmdbuffer != NULL){
	    free(cmdbuffer);
	    cmdbuffer = NULL;
	}

	if (snapshotBuffer != NULL) {
		free(snapshotBuffer) ;
		snapshotBuffer = NULL ;
	}
	
    pthread_mutex_destroy(&cmd_mutex);
    pthread_cond_destroy(&cmd_sync);
    clearPreviewFrame();
	if(cmdFd>0){
		close(cmdFd) ;
	}
	if(fd>0){
     close(fd);
	}
    return ret ;
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeSendCmd(JNIEnv *env, jobject instance, jint fd,
                                                     jint requesttype, jint request, jint value,
                                                     jint index, jint length, jbyteArray data_) {
	
    jbyte *data = NULL;

	int ret = -1 , dataSize = 512 ;
	
	//+++++++++++++
	if( isAnNumFlag == FALSE || fd<0)
		return ret ;
	//-------------

	
    if (data_)
        data = env->GetByteArrayElements(data_, NULL);
//    LOGE("nativeSendCmd 1 tid=%d,requesttype=%x,request=%d",gettid(),requesttype,request);



    pthread_mutex_lock(&cmd_mutex);
    {
        if (cmdbuffer == NULL)
            int nTemp = posix_memalign((void **) &cmdbuffer, getpagesize(), CMD_DATA_LEN);

        if (cmdbuffer) {
            memset(cmdbuffer, 0, CMD_DATA_LEN);

			if(getBoardVer()){				
				p_vsd_cmd packet = (p_vsd_cmd) cmdbuffer;
				packet->cmd = request;
				packet->para_len = length;
				memcpy(&packet->paraAddr, data, length);
			}else{
				p_vsd_cmd_b packet = (p_vsd_cmd_b) cmdbuffer;
				packet->cmd = request;
				packet->para_len = length;
				memcpy(packet->para , data, length);
			}

            lseek(fd, 0, SEEK_SET);
 			if(length > 508){
				dataSize = (((length>>9)+2)<<9) ;
				if(dataSize > CMD_DATA_LEN){
					return -1 ;
				}
			}


            int wlen = write(fd, cmdbuffer, dataSize);


            if (wlen > 0) {
                memset(cmdbuffer, 0, CMD_DATA_LEN);
				ret = 0;
				
#if 1 // 20180929
				if(request>= 23){// start at cmd [CAM_SET_ADAS_CODE]
					lseek(fd, 512 , SEEK_SET);
					int wlen = read(fd, cmdbuffer, dataSize);
					if(wlen>0){
						memcpy(data , cmdbuffer , length) ;
					}
				}
#endif	

            } else {
                LOGE("write cmd errro,code=%d,fd=%d", errno, fd);
            }


        }

    }

    pthread_mutex_unlock(&cmd_mutex);
    if (data)
        env->ReleaseByteArrayElements(data_, data, 0);
    return ret;
}


JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_setLanePara(JNIEnv *env, jobject instance,
                                                     jint is_right , jint start_x, jint start_y,
                                                     jfloat slope , jint w , jint h , jint threshold ,
                                                     jint thresholdU , jint thresholdV) {
	int ret = 0 ;

	setlanePosData((u8)is_right , start_x , start_y , slope , w , h , (u8)threshold , (u8)thresholdU ,
		(u8)thresholdV) ;

    return ret;
}

static LANE_PARA lanePara ;
JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_getLanePara(JNIEnv *env, jobject instance,
                                                     jint is_right , jbyteArray data_) {
	int ret = 0 ;
	float tmpSlope ;
	jbyte *data = NULL;
    if (data_)
        data = env->GetByteArrayElements(data_, NULL);

	memset(&lanePara , 0 , sizeof(lanePara)) ;
	getlanePosData(is_right , (u32*)&lanePara.startX, (u32*)&lanePara.startY , (float*)&tmpSlope, (u32*)&lanePara.w , 
		(u32*)&lanePara.h, (u8*)&lanePara.threshold_y , (u8*)&lanePara.threshold_u , (u8*)&lanePara.threshold_v) ;


	memcpy(data , &lanePara , sizeof(lanePara) ) ;

    if (data)
        env->ReleaseByteArrayElements(data_, data, 0);

    return ret;
}


JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_setLanePos(JNIEnv *env, jobject instance,
                                                     jint start_x, jint start_y) {
	int ret = 0 ;

	setlanePos( start_x , start_y ) ;

//	debugl("set center x:[%d] - y:[%d]" ,  start_x , start_y) ;

    return ret;
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_getLanePos(JNIEnv *env, jobject instance,
                                                     jbyteArray data_) {
    int ret = 0 ;
	jbyte *data = NULL;
    if (data_)
        data = env->GetByteArrayElements(data_, NULL);

	getlanePos((u32*)data , (u32*)(data+4)) ;

//	debugl("get center x:[%d] - y:[%d]" ,  *(u32*)data , *(u32*)(data+4)) ;

    if (data)
        env->ReleaseByteArrayElements(data_, data, 0);

    return ret;
}




JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeGetFile(JNIEnv *env, jobject instance, jint fd,
                                                     jbyteArray data_ , jint length) {
    jbyte *data = NULL;
    if (data_) {

   		u32 tmpLength = ((length>>9)+1)<<9 ;
        size_t tmp = posix_memalign((void **) &data, 512 , tmpLength);
		lseek(fd , 512 , SEEK_SET);//0

        read(fd, data , tmpLength);

        env->SetByteArrayRegion( data_ , 0 , length , data) ;

		if(data)
			free(data) ;
        return 0;
    }
    return -1;
}


JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeSetFrameCallback(JNIEnv *env, jobject instance,
                                                              jint fd,
                                                              jobject callback) {

    if (callback) {
        pthread_mutex_lock(&preview_mutex);
        {
            if (!env->IsSameObject(mFrameCallbackObj, callback)) {//???????????????????????????
                if (mFrameCallbackObj) {
                    env->DeleteGlobalRef(mFrameCallbackObj);//?????? obj ????????????????????????
                }
                mFrameCallbackObj = env->NewGlobalRef(callback);//?????? obj ?????????????????????????????????????????????????????????????????? DeleteGlobalRef() ?????????????????? ?????????????????????????????????????????????????????? NULL???
                // get method IDs of Java object for callback
                jclass clazz = env->GetObjectClass(callback);
                if (LIKELY(clazz)) {
                    md_callback = env->GetMethodID(clazz,
                                                   "onFrame", "([B)V");
                } else {
                    LOGE("failed to get object class");
                }
                env->ExceptionClear();
            }
        }
        pthread_mutex_unlock(&preview_mutex);
    }
}

JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_initGles(JNIEnv *env, jobject _instance, jint pWidth,
                                                jint pHeight) {
   // LOGE("init() gles");
    pthread_mutex_lock(&capture_mutex);
    instance = (Instance *) malloc(sizeof(Instance));
    memset(instance, 0, sizeof(Instance));
    //	1.??????????????????
    GLuint shaders[2] = {0};
    shaders[0] = initShader(codeVertexShader, GL_VERTEX_SHADER);
    shaders[1] = initShader(codeFragShader, GL_FRAGMENT_SHADER);
    instance->pProgram = initProgram(shaders, 2);
    instance->maMVPMatrixHandle = glGetUniformLocation(instance->pProgram, "uMVPMatrix");
    instance->maPositionHandle = glGetAttribLocation(instance->pProgram, "aPosition");
    instance->maTexCoorHandle = glGetAttribLocation(instance->pProgram, "aTexCoor");
    instance->myTextureHandle = glGetUniformLocation(instance->pProgram, "yTexture");
    instance->muTextureHandle = glGetUniformLocation(instance->pProgram, "uTexture");
    instance->mvTextureHandle = glGetUniformLocation(instance->pProgram, "vTexture");
    //	2.???????????????
    //		2.1????????????id
    glGenTextures(1, &instance->yTexture);
    glGenTextures(1, &instance->uTexture);
    glGenTextures(1, &instance->vTexture);
  //  LOGE("init() yT = %d, uT = %d, vT = %d.", instance->yTexture, instance->uTexture,
   //      instance->vTexture);
    //LOGE("%s %d error = %d", __FILE__, __LINE__, glGetError());
    //	3.??????Yuv????????????
    instance->yBufferSize = sizeof(char) * pWidth * pHeight;
    instance->uBufferSize = sizeof(char) * pWidth / 2 * pHeight / 2;
    instance->vBufferSize = sizeof(char) * pWidth / 2 * pHeight / 2;
    instance->yBuffer = (unsigned char *) (char *) malloc(instance->yBufferSize);
    instance->uBuffer = (unsigned char *) (char *) malloc(instance->uBufferSize);
    instance->vBuffer = (unsigned char *) (char *) malloc(instance->vBufferSize);
    memset(instance->yBuffer, 0, instance->yBufferSize);
    memset(instance->uBuffer, 0, instance->uBufferSize);
    memset(instance->vBuffer, 0, instance->vBufferSize);
    instance->pHeight = pHeight;
    instance->pWidth = pWidth;
    instance->state = 0;
  //  LOGE("width = %d, height = %d", instance->pWidth, instance->pHeight);
    //????????????
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    //glClearColor(0.0, 0.0, 1.0, 1.0);
    //glClear(GL_COLOR_BUFFER_BIT);



//2???????????????????????????????????? a????????????????????????

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#if 0
//b???????????????????????? glEnable(GL_POINT_SMOOTH);

    glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);

//????????????????????????????????????????????????????????????????????????????????????
//3???????????????????????????????????? //??????????????????
    glEnable(GL_MULTISAMPLE);
//???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
//4??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????

#endif
    //??????????????????
//	glEnable(GL_DEPTH_TEST);
  //  LOGE("%s %d error = %d", __FILE__, __LINE__, glGetError());
    pthread_mutex_unlock(&capture_mutex);
}

JNIEXPORT jstring JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_initUvcCameraTest(JNIEnv *env, jobject instance,
                                                         jstring _devpath) {
//    char dev[] = "/mnt/udisk/udisk2/akfile";
//    char root[]="/mnt/udisk";
   // LOGE("uvccamera-lib initUvcCamera");
    pthread_mutex_init(&cmd_mutex, NULL);
    pthread_cond_init(&cmd_sync, NULL);
    int fd = -1;
    const char *devpath = env->GetStringUTFChars(_devpath, FALSE);
//	const char devpath[] = "/storage/4C3B-5CF7/VSFILE" ;
    LOGE("start init uvccamera devpath=%s", devpath);
    struct stat info;
    int ret = stat(devpath, &info);
 //   LOGE("state ret=%d", ret);
    if (devpath != NULL) {
        if(isPx3){
            fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY);
        } else{
            fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY,
                  S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        }


        if (fd == -1) {
            LOGE("open readonly");
            if(isPx3){
                fd = open(devpath, O_DIRECT | O_NOCTTY);
            } else{
                fd = open(devpath, O_DIRECT | O_NOCTTY,
                          S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
            }


            //           fd = open(devpath, O_RDONLY ) ; // S_IRUSR | S_IRGRP  | S_IROTH );

            if(fd<0){
                LOGE("init uvccamera cmd fd=%d,errorcode=[%d]:{%s},tid=%d", fd, errno, strerror(errno), gettid());
                fd = errno ;
            }
        }
//        uvcPreview.initCamera(devpath);
        LOGE("init uvccamera fd=%d,errorcode=%d", fd, errno);
    }
    env->ReleaseStringUTFChars(_devpath, devpath);
    return env->NewStringUTF(strerror(errno));
}

JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_changeESLayout(JNIEnv *env, jobject _instance, jint width,
                                                      jint height) {

    pthread_mutex_lock(&capture_mutex);
    if (instance != 0) {
        instance->vWidth = width;
        instance->vHeight = height;
    }

    unsigned int eW = width, eH = height;

    glViewport(0, 0, eW, eH);


    pthread_mutex_unlock(&capture_mutex);
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_setPx3(JNIEnv *env, jobject instance , jboolean px3) {
    isPx3 =  px3 ;
    return 1 ;
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_drawESFrame(JNIEnv *env, jobject _instance) {

    int ret = -1;



    pthread_mutex_lock(&capture_mutex);
    if (instance != NULL) {
        uvc_frame_t *yuv_frame = waitYuvFrame();
        ret = -2;
        if (yuv_frame != NULL) {
#if 1
		if(isUpLoadAdasData == 0){
			Handler456((u8*)yuv_frame->data , &isReport) ;
		}
#endif
			#if DECODE_YUV420P_EN
				memcpy(instance->yBuffer, yuv_frame->data, instance->yBufferSize);
				memcpy(instance->uBuffer, &(((unsigned char *) yuv_frame->data)[yuv_frame->width * yuv_frame->height]), instance->vBufferSize);
				memcpy(instance->vBuffer, &(((unsigned char *) yuv_frame->data)[yuv_frame->width*yuv_frame->height*5/4]), instance->uBufferSize);
			#else
				memcpy(instance->yBuffer, yuv_frame->data, instance->yBufferSize);
				memcpy(instance->vBuffer, &(((unsigned char *) yuv_frame->data)[yuv_frame->width * yuv_frame->height]), instance->vBufferSize);
				memcpy(instance->uBuffer, &(((unsigned char *) yuv_frame->data)[yuv_frame->width*yuv_frame->height*5/4]), instance->uBufferSize);
			#endif

            instance->state = 1;
            recycle_frame(yuv_frame);
            ret = 0;
//            yuv_frame=NULL;
//            LOGE("ydata=%x,%x,%x,%x",((char *)instance->yBuffer)[0],((char *)instance->yBuffer)[1],((char *)instance->yBuffer)[2],((char *)instance->yBuffer)[3]);
        }
        drawFrame(instance);
    }
    pthread_mutex_unlock(&capture_mutex);
    return ret;
}

JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeAdasFrameCallback(JNIEnv *env, jobject instance,
                                                               jobject callback) {
    if (callback) {
        pthread_mutex_lock(&preview_mutex);
        {
            if (!env->IsSameObject(mAdasCallbackObj, callback)) {
                if (mAdasCallbackObj) {
                    env->DeleteGlobalRef(mAdasCallbackObj);
                }
                mAdasCallbackObj = env->NewGlobalRef(callback);
                // get method IDs of Java object for callback
                jclass clazz = env->GetObjectClass(callback);
                if (LIKELY(clazz)) {
                    mdAdas_callback = env->GetMethodID(clazz,
                                                       "onFrame", "([B)V");


//					debugl("nativeAdasFrameCallback success...") ;
                } else {
//                    LOGE("failed to get object class");
                }
                env->ExceptionClear();
            }
        }
        pthread_mutex_unlock(&preview_mutex);
    }
}


JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeSetMainRuning(JNIEnv *env, jobject instance,
                                                           jboolean run) {
    isMainRunning = run;
}


JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_GetUploadAdasDataStatus(JNIEnv *env, jobject instance) {
#if UPLOAD_ADAS_DATA_EN
	return isUpLoadAdasData ;
#else
	return 0 ;
#endif	
}


JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_SetUploadAdasDataStatus(JNIEnv *env, jobject instance , jboolean enable) {
#if UPLOAD_ADAS_DATA_EN
	isUpLoadAdasData = enable ;
#endif	
}



JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_GetLibDispStatus(JNIEnv *env, jobject instance) {
	int tmpValue ;

	pthread_mutex_lock(&decode_mutex);
	tmpValue = isReadVsDataAndDecode ;
	pthread_mutex_unlock(&decode_mutex) ;
	
	return tmpValue ;
}


JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_SetLibDispStatus(JNIEnv *env, jobject instance , jboolean enable) {
	pthread_mutex_lock(&decode_mutex);
	isReadVsDataAndDecode = enable ;
	pthread_mutex_unlock(&decode_mutex) ;
}



JNIEXPORT jboolean JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeTakesnoshot(JNIEnv *env, jobject instance,
                                                         jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);
    LOGE("snappath=%s", path);
    jboolean result = JNI_FALSE;
    int fd = open(path, O_RDWR | O_CREAT);
    if (fd < 0) {
        goto end;
    }
    if (snapshotBuffer == NULL) {
        snapshotBuffer = (char *) malloc(300 * 1024);
    }
    snapshotSize = 0;
    isSnapshot = TRUE;
    pthread_mutex_lock(&snap_mutex);
    struct timespec tv;
    clock_gettime(CLOCK_REALTIME, &tv);
    tv.tv_sec += 5;//-???????????????30?????????????????????????????????
    pthread_cond_timedwait(&snap_sync, &snap_mutex, &tv);
    pthread_mutex_unlock(&snap_mutex);

    if (snapshotSize > 0) {
        write(fd, snapshotBuffer, snapshotSize);
        result = JNI_TRUE;
    }
    end:
    if (fd >= 0)
        close(fd);
    env->ReleaseStringUTFChars(path_, path);
    return result;
}


JNIEXPORT jstring JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_initUvcCmd(JNIEnv *env, jobject instance, jstring devpath_) {
    const char *devpath = env->GetStringUTFChars(devpath_, 0);
 //   LOGE("initUvcCmd dev=%s", devpath);
    int fd = -1;
    if (devpath != NULL) {
        if(isPx3){
            fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY);
        } else{
                    fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY,
                  S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        }

//        uvcPreview.initCamera(devpath);
//        LOGE("init uvccamera cmd fd=%d,errorcode=%d,tid=%d", fd, errno, gettid());
//        if(fd<=0){
//            fd=errno;
//        }
		if(fd>0){
			cmdFd = fd ;
		}
    }
    env->ReleaseStringUTFChars(devpath_, devpath);
    char result[50];
    char* error = strerror(errno);
    sprintf(result,"%d_%s",fd,error);
    //env->NewStringUTF(strerror(errno)
    return env->NewStringUTF(result);
//    return fd;
}

JNIEXPORT jint JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_initUvcFile(JNIEnv *env, jobject instance,
                                                   jstring devpath_) {
    const char *devpath = env->GetStringUTFChars(devpath_, 0);
//    LOGE("initUvcCmd dev=%s", devpath);
    int fd = -1;
    if (devpath != NULL) {
        if(isPx3){
            fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY);
        } else{
                    fd = open(devpath, O_RDWR | O_DIRECT | O_NOCTTY,
                  S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        }

//        uvcPreview.initCamera(devpath);
//        LOGE("init uvccamera cmd fd=%d,errorcode=[%d]:{%s},tid=%d", fd, errno, strerror(errno), gettid());
//        if(fd<=0){
//            fd=errno;
//        }
    }
    env->ReleaseStringUTFChars(devpath_, devpath);
    return fd;
}

JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeFrameCallback(JNIEnv *env, jobject instance,
                                                           jobject callback) {
//    LOGE("init uvccamera callback");
    if (callback) {
        pthread_mutex_lock(&capture_mutex);
        {
            if (!env->IsSameObject(mFrameCallbackObj, callback)) {
                if (mFrameCallbackObj) {
                    env->DeleteGlobalRef(mFrameCallbackObj);
                }
                mFrameCallbackObj = env->NewGlobalRef(callback);
                // get method IDs of Java object for callback
                jclass clazz = env->GetObjectClass(callback);
                if (LIKELY(clazz)) {
                    md_callback = env->GetMethodID(clazz,
                                                   "onFrame", "([B)V");
                   // LOGE("init uvccamera callback111 %d",md_callback);
                } else {
//                    LOGE("failed to get object class");
                }
                env->ExceptionClear();
            }
        }
        pthread_mutex_unlock(&capture_mutex);
    }
}

JNIEXPORT void JNICALL
Java_com_huiying_cameramjpeg_UvcCamera_nativeStateFrameCallback(JNIEnv *env, jobject instance,
                                                           jobject callback) {
//    LOGE("init stateFrame callback");
    if (callback) {
        pthread_mutex_lock(&capture_mutex);
        {
            if (!env->IsSameObject(mStateCallbackObj, callback)) {
                if (mStateCallbackObj) {
                    env->DeleteGlobalRef(mStateCallbackObj);
                }
                mStateCallbackObj = env->NewGlobalRef(callback);
                // get method IDs of Java object for callback
                jclass clazz = env->GetObjectClass(callback);
                if (LIKELY(clazz)) {

					mdState_callback = env->GetMethodID(clazz , "onFrame" , "([B)V");
					
//                    LOGE("init stateFrame callback ok:0x%x" , mdState_callback);
                } else {
//                    LOGE("failed to get stateFrame object class");
                }
                env->ExceptionClear();
            }
        }
        pthread_mutex_unlock(&capture_mutex);
    }
}


}




